import { ArrayUtils } from "../../../utils";
import { PlanetProduct } from "../entity/PlanetProduct";
import { useCacheStore } from "../../../sde/cache";
import type { UniverseType } from "../../../sde/entity";
import type { PlanetFactory } from "../entity/PlanetFactory";

export class PlanetUtils {
  /**
   * 获取标准周期内工厂需要输入的资源
   * @param factories 工厂
   * @param level 指定资源等级
   */
  static getFactoryInputsByCycle(factories: PlanetFactory[], level: 0 | 1 | 2 | 3) {
    return ArrayUtils.groupAccumulate(
      factories.flatMap((f) => {
        return f.inputs
          .filter((input) => {
            //p0
            if (input.type?.parent?.parent?.id === 42 && level === 0) {
              return true;
            }
            //p1
            if (input.type.groupId === 1042 && level === 1) {
              return true;
            }
            //p2
            if (input.type.groupId === 1034 && level === 2) {
              return true;
            }
            //p3
            if (input.type.groupId === 1040 && level === 3) {
              return true;
            }
            return false;
          })
          .map((e) => e);
      }),
      (input) => input.id,
      (input) => input.cycleCount!
    );
  }

  /**
   * 获取标准周期内工厂的产出
   * @param factories 所有工厂
   * @param level 产出物级别
   * @private
   */
  static getFactoryOutputsByCycle(factories: PlanetFactory[], level: 1 | 2 | 3) {
    return ArrayUtils.groupAccumulate(
      factories
        .filter((factory) => {
          if (factory.name.includes("基础") && level === 1) {
            return true;
          }
          if (factory.name.includes("高级")) {
            if (level === 2) {
              return factory.output?.type.groupId === 1034;
            }
            if (level === 3) {
              return factory.output?.type.groupId === 1040;
            }
          }
          return false;
        })
        .map((f) => f.output!),
      (e) => e.id,
      (e) => e.cycleCount!
    );
  }

  static getTotalOutputStatistics(factories: PlanetFactory[]) {
    const inputs = factories.flatMap((f) => f.inputs);
    const outputs = factories
      .map((f) => f.output)
      .filter((f) => f)
      .map((f) => f as PlanetProduct);
    const inputCountsByType = inputs.reduce((acc, input: PlanetProduct) => {
      acc[input.type.id] = (acc[input.type.id] || 0) + (input.count ?? 0);
      return acc;
    }, {} as Record<number, number>);

    // 计算未使用的产出
    const individualUnusedOutputs: PlanetProduct[] = outputs
      .map((output: PlanetProduct) => {
        const inputCount = inputCountsByType[output.type.id] ?? 0;
        const unusedCount = output.count - inputCount;
        return new PlanetProduct(Math.max(unusedCount, 0), output.type, output.cycleCount);
      })
      .filter((output) => output.count > 0);

    // 聚合同类型的未使用产出
    return individualUnusedOutputs.reduce((acc, output) => {
      const existing = acc.find((item) => item.type.id === output.type.id);
      if (existing) {
        existing.count += output.count;
        existing.cycleCount = (existing.cycleCount ?? 0) + (output.cycleCount ?? 0);
      } else {
        acc.push(output);
      }
      return acc;
    }, [] as PlanetProduct[]);
  }

  static getTotalInputStatistics(factories: PlanetFactory[], primitiveResource: PlanetProduct[]) {
    return [
      PlanetUtils.calcInputStatistics(
        factories,
        ArrayUtils.groupAccumulate(
          primitiveResource,
          (e) => e.id,
          (e) => e.cycleCount!
        ),
        0
      ),
      PlanetUtils.calcInputStatistics(factories, PlanetUtils.getFactoryOutputsByCycle(factories, 1), 1),
      PlanetUtils.calcInputStatistics(factories, PlanetUtils.getFactoryOutputsByCycle(factories, 2), 2),
      PlanetUtils.calcInputStatistics(factories, PlanetUtils.getFactoryOutputsByCycle(factories, 3), 3),
    ].flatMap((products) => products);
  }

  static calcInputStatistics(factories: PlanetFactory[], outerResources: Map<number, number>, level: 0 | 1 | 2 | 3) {
    const cacheStore = useCacheStore();
    const inputs = PlanetUtils.getFactoryInputsByCycle(factories, level);
    return Array.from(inputs.keys()).map((inputId) => {
      const need = inputs.get(inputId);
      const produce = outerResources.get(inputId) ?? 0;
      return new PlanetProduct(produce - need!, cacheStore.getType(inputId)!, produce - need!);
    });
  }
  static accumulatePlanetProduct(resources: PlanetProduct[]): PlanetProduct[] {
    const map = new Map<number, { totalCount: number; totalCycleCount: number; type: UniverseType }>();

    resources.forEach((product) => {
      const typeId = product.type.id;
      if (!map.has(typeId)) {
        map.set(typeId, { totalCount: 0, totalCycleCount: 0, type: product.type });
      }
      const existing = map.get(typeId)!;
      existing.totalCount += product.count;
      existing.totalCycleCount += product.cycleCount || 0;
    });

    return Array.from(map.values()).map(({ totalCount, totalCycleCount, type }) => {
      return new PlanetProduct(totalCount, type, totalCycleCount);
    });
  }
}
